Stimuli list
Intensity analysis per speaker
dataWrd %>%
filter(substr (snd3,1,1) == "a" | substr (snd3,2,2) == "a") %>%
group_by (speaker, wordType, conditionNorm) %>%
summarise(n = n(),
mInt = mean (snd2IntNorm),
sdInt = sd (snd2IntNorm)) %>%
pivot_longer(names_to = "stats", values_to = "values", n:sdInt) %>%
pivot_wider(names_from = c(wordType, stats), values_from = "values")
Duration analysis per speaker
dataWrd %>%
group_by (speaker, wordType, conditionNorm) %>%
summarise(n = n(),
mInt = mean (lDur),
sdInt = sd (lDur)) %>%
pivot_longer(names_to = "stats", values_to = "values", n:sdInt) %>%
pivot_wider(names_from = c(wordType, stats), values_from = "values")
A1-H1 intensity difference analysis per speaker
dataWrd %>%
filter (
(substr (snd3,1,1) == "a" | substr (snd3,2,2) == "a") &
is.na (a1h1Int) == FALSE &
conditionNorm != "Carrier phrase" &
!(speaker == "M69" & conditionNorm == "Individual words") &
!(speaker == "M50" & conditionNorm == "Individual words")) %>%
group_by (speaker, conditionNorm, wordType) %>%
summarise (n = n(),
a1h1m = mean (a1h1Int),
a1h1sd = sd (a1h1Int)) %>%
pivot_longer(names_to = "stats", values_to = "values", n:a1h1sd) %>%
pivot_wider(names_from = c(wordType, stats), values_from = "values")
A2-H1 intensity difference analysis per speaker
dataWrd %>%
filter (
(substr (snd3,1,1) == "a" | substr (snd3,2,2) == "a") &
is.na (a1h1Int) == FALSE &
conditionNorm != "Carrier phrase" &
!(speaker == "M69" & conditionNorm == "Individual words") &
!(speaker == "M50" & conditionNorm == "Individual words")) %>%
group_by (speaker, conditionNorm, wordType) %>%
summarise (n = n(),
a2h1m = mean (a2h1Int),
a2h1sd = sd (a2h1Int)) %>%
pivot_longer(names_to = "stats", values_to = "values", n:a2h1sd) %>%
pivot_wider(names_from = c(wordType, stats), values_from = "values")
H2-H1 intensity difference analysis per speaker
dataWrd %>%
filter (
(substr (snd3,1,1) == "a" | substr (snd3,2,2) == "a") &
is.na (a1h1Int) == FALSE &
conditionNorm != "Carrier phrase" &
!(speaker == "M69" & conditionNorm == "Individual words") &
!(speaker == "M50" & conditionNorm == "Individual words")) %>%
group_by (speaker, conditionNorm, wordType) %>%
summarise (n = n(),
h2h1m = mean (h2h1Int),
h2h1sd = sd (h2h1Int)) %>%
pivot_longer(names_to = "stats", values_to = "values", n:h2h1sd) %>%
pivot_wider(names_from = c(wordType, stats), values_from = "values")
Pulse and intensity profiles
lapply(unique(dataWrd$speaker), function(i){
if (i == "F45") {
# exclude "j_ilˀi_nno" from F45. Glottal stop
# exclude "kul_ilo_jd" from F45 - creak on /l/ in the end of a sentence
tmp <- data %>% filter (speaker == i &
word != "j_ilˀ^i_nno" & word != "kul_il^o_jd")
} else{
tmp <- data %>% filter (speaker == i)
}
# convert intervals between pulses to milliseconds
tmp$plsIntvl <- tmp$plsIntvl * 1000
# plot pulse profiles
tmp %>%
ggplot (aes (x = pointsNorm, y = plsIntvl)) +
geom_line (aes(colour = conditionWord)) +
xlab ("sound timing, % of total, laterals are in [0, 1]") +
ylab ("pulse interval duration, ms") +
geom_vline (xintercept = 1, linetype = "dotted", color = "black") +
geom_vline (xintercept = 0, linetype = "dotted", color = "black") +
theme (legend.key.width = unit (0.5, "line"),
legend.position = "none",
axis.text.x = element_text(size = 12),
axis.text.y = element_text(size = 12),
axis.title.x = element_text(size = 12),
axis.title.y = element_text(size = 12),
strip.text.x = element_text(size = 12),
strip.text.y = element_text(size = 12)) +
scale_x_continuous(breaks = c(-2, -1, 0, 1, 2, 3), labels = c("-2", "-1", "0", "1", "2", "3")) +
scale_color_grey(start = 0.8, end = 0.2) +
annotate ("text", x = -0.7, y = 35, label = "/vowel/", size = 4.5) +
annotate ("text", x = 0.5, y = 35, label = "/lateral/", size = 4.5) +
annotate ("text", x = 2, y = 35, label = "/vowel/", size = 4.5) +
facet_grid (~conditionNorm~wordType, scales = "free")+
ggtitle(i) ->
p1
# plot intensity profiles
tmp %>%
ggplot (aes (x = pointsNorm, y = intensityOrig)) +
geom_line (aes(colour = conditionWord)) +
xlab ("Sound timing, % of total, laterals are in [0, 1]") +
ylab ("Sound intensity,dB") +
ylim (40, 85) +
geom_vline (xintercept = 1, linetype = "dotted", color = "black") +
geom_vline (xintercept = 0, linetype = "dotted", color = "black") +
theme (legend.key.width = unit (0.5, "line"),
#legend.text = element_text(size = rel(0.75)),
#legend.text = element_blank(),
#legend.title = element_blank(),
legend.position = "none",
axis.text.x = element_text(size = 12),
axis.text.y = element_text(size = 12),
axis.title.x = element_text(size = 12),
axis.title.y = element_text(size = 12),
strip.text.x = element_text(size = 12),
strip.text.y = element_text(size = 12)) +
scale_x_continuous(breaks = c(-2, -1, 0, 1, 2, 3), labels = c("-2", "-1", "0", "1", "2", "3")) +
scale_color_grey(start = 0.8, end = 0.2) +
annotate ("text", x = -1, y = 85, label = "/vowel/", size = 4.5) +
annotate ("text", x = 0.5, y = 85, label = "/lateral/", size = 4.5) +
annotate ("text", x = 2, y = 85, label = "/vowel/", size = 4.5) +
facet_wrap (~conditionNorm~wordType, ncol = 2) +
ggtitle(i) ->
p2
return(list(p1, p2))
})
[[1]]
[[1]][[1]]
[[1]][[2]]
[[2]]
[[2]][[1]]
[[2]][[2]]
[[3]]
[[3]][[1]]
[[3]][[2]]
[[4]]
[[4]][[1]]
[[4]][[2]]
[[5]]
[[5]][[1]]
[[5]][[2]]
[[6]]
[[6]][[1]]
[[6]][[2]]
[[7]]
[[7]][[1]]
[[7]][[2]]
[[8]]
[[8]][[1]]
[[8]][[2]]
[[9]]
[[9]][[1]]
[[9]][[2]]
[[10]]
[[10]][[1]]
[[10]][[2]]
Model printouts
dataWrd %>%
filter ((substr (snd3,1,1) == "a" | substr (snd3,2,2) == "a"),
conditionNorm != "Carrier phrase") %>%
mutate(cond = conditionNorm,
speaker = factor(speaker,
levels = c ("F30", "M35", "M40", "F45", "F49", "M50",
"M52", "M60", "M69", "M75")),
intensity = snd2IntNorm,
sound = wordType,
sound = ifelse(sound == "l", "l", "glottolised l")) %>%
lmer (intensity ~ cond*sound + (1|speaker), data = .) %>%
summary()
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula: intensity ~ cond * sound + (1 | speaker)
Data: .
REML criterion at convergence: 855.1
Scaled residuals:
Min 1Q Median 3Q Max
-3.4672 -0.4874 0.1502 0.6561 1.9824
Random effects:
Groups Name Variance Std.Dev.
speaker (Intercept) 3.972 1.993
Residual 12.930 3.596
Number of obs: 157, groups: speaker, 10
Fixed effects:
Estimate Std. Error df t value Pr(>|t|)
(Intercept) 68.3717 0.9087 17.8625 75.243 < 2e-16 ***
condIndividual words -6.8749 0.9861 106.3475 -6.972 2.75e-10 ***
soundl 1.6607 0.8911 144.6487 1.864 0.0644 .
condIndividual words:soundl 6.5213 1.1874 144.3826 5.492 1.74e-07 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Correlation of Fixed Effects:
(Intr) cndInw soundl
cndIndvdlwr -0.576
soundl -0.338 0.316
cndIndwrds: 0.253 -0.500 -0.751
dataWrd %>%
mutate(duration = lDur,
speaker = factor (speaker,
levels = c ("F30", "M35", "M40", "F45", "F49", "M50",
"M52", "M60", "M69", "M75")),
sound = wordType,
sound = ifelse(sound == "l", "l", "glottolised l"),
cond = conditionNorm,
maxPulse = plsMax) %>%
lmer (duration ~ cond * sound + (1|speaker), data = .) %>%
summary()
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula: duration ~ cond * sound + (1 | speaker)
Data: .
REML criterion at convergence: -1785
Scaled residuals:
Min 1Q Median 3Q Max
-1.9936 -0.6010 -0.1667 0.5333 5.5146
Random effects:
Groups Name Variance Std.Dev.
speaker (Intercept) 0.0001662 0.01289
Residual 0.0004980 0.02231
Number of obs: 390, groups: speaker, 10
Fixed effects:
Estimate Std. Error df t value Pr(>|t|)
(Intercept) 0.111552 0.006445 40.503004 17.309 < 2e-16
condFree narrative -0.036647 0.006107 364.719230 -6.001 4.73e-09
condIndividual words 0.025651 0.005623 374.469031 4.562 6.88e-06
soundl -0.010490 0.006887 374.469031 -1.523 0.129
condFree narrative:soundl 0.001862 0.007534 374.872343 0.247 0.805
condIndividual words:soundl -0.002478 0.007952 374.469031 -0.312 0.756
(Intercept) ***
condFree narrative ***
condIndividual words ***
soundl
condFree narrative:soundl
condIndividual words:soundl
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Correlation of Fixed Effects:
(Intr) cndFrn cndInw soundl cndFn:
condFrnrrtv -0.682
cndIndvdlwr -0.654 0.691
soundl -0.534 0.564 0.612
cndFrnrrtv: 0.496 -0.638 -0.560 -0.914
cndIndwrds: 0.463 -0.488 -0.707 -0.866 0.792
dataWrd %>%
filter ((substr (snd3,1,1) == "a" | substr (snd3,2,2) == "a") &
is.na (a1h1Int) == FALSE &
conditionNorm != "Carrier phrase" &
!(speaker == "M69" & conditionNorm == "Individual words") &
!(speaker == "M50" & conditionNorm == "Individual words")) %>%
mutate(cond = conditionNorm,
speaker = factor (speaker,
levels = c ("F30", "M35", "M40", "F45", "F49", "M50",
"M52", "M60", "M69", "M75")),
sound = wordType,
sound = ifelse(sound == "l", "l", "glottolised l")) %>%
lmer(a1h1Int ~ cond * sound + (1|speaker), data = .) %>%
summary()
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula: a1h1Int ~ cond * sound + (1 | speaker)
Data: .
REML criterion at convergence: 822.7
Scaled residuals:
Min 1Q Median 3Q Max
-2.4428 -0.6115 -0.0417 0.6604 3.4829
Random effects:
Groups Name Variance Std.Dev.
speaker (Intercept) 13.69 3.700
Residual 28.87 5.373
Number of obs: 132, groups: speaker, 9
Fixed effects:
Estimate Std. Error df t value Pr(>|t|)
(Intercept) 7.812 1.636 12.576 4.777 0.000396 ***
condIndividual words 3.924 1.913 63.086 2.051 0.044385 *
soundl -2.709 1.332 120.473 -2.034 0.044179 *
condIndividual words:soundl -3.955 1.933 120.277 -2.046 0.042887 *
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Correlation of Fixed Effects:
(Intr) cndInw soundl
cndIndvdlwr -0.530
soundl -0.285 0.254
cndIndwrds: 0.195 -0.442 -0.689
dataWrd %>%
filter ((substr (snd3,1,1) == "a" | substr (snd3,2,2) == "a") &
is.na (a1h1Int) == FALSE &
conditionNorm != "Carrier phrase" &
!(speaker == "M69" & conditionNorm == "Individual words") &
!(speaker == "M50" & conditionNorm == "Individual words")) %>%
mutate(cond = conditionNorm,
speaker = factor (speaker,
levels = c ("F30", "M35", "M40", "F45", "F49", "M50",
"M52", "M60", "M69", "M75")),
sound = wordType,
sound = ifelse(sound == "l", "l", "glottolised l")) %>%
lmer(a2h1Int ~ cond * sound + (1|speaker), data = .) %>%
summary()
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula: a2h1Int ~ cond * sound + (1 | speaker)
Data: .
REML criterion at convergence: 923.6
Scaled residuals:
Min 1Q Median 3Q Max
-2.54010 -0.58715 0.08819 0.68865 2.34891
Random effects:
Groups Name Variance Std.Dev.
speaker (Intercept) 35.21 5.934
Residual 62.99 7.937
Number of obs: 132, groups: speaker, 9
Fixed effects:
Estimate Std. Error df t value Pr(>|t|)
(Intercept) -12.1978 2.5533 13.2051 -4.777 0.000346 ***
condIndividual words 3.0378 2.8837 72.1810 1.053 0.295662
soundl -0.5526 1.9680 120.8816 -0.281 0.779357
condIndividual words:soundl -6.4067 2.8549 120.7179 -2.244 0.026646 *
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Correlation of Fixed Effects:
(Intr) cndInw soundl
cndIndvdlwr -0.515
soundl -0.270 0.250
cndIndwrds: 0.184 -0.434 -0.689
dataWrd %>%
filter ((substr (snd3,1,1) == "a" | substr (snd3,2,2) == "a") &
is.na (a1h1Int) == FALSE &
conditionNorm != "Carrier phrase" &
!(speaker == "M69" & conditionNorm == "Individual words") &
!(speaker == "M50" & conditionNorm == "Individual words")) %>%
mutate(cond = conditionNorm,
speaker = factor (speaker,
levels = c ("F30", "M35", "M40", "F45", "F49", "M50",
"M52", "M60", "M69", "M75")),
sound = wordType,
sound = ifelse(sound == "l", "l", "glottolised l")) %>%
lmer(h2h1Int ~ cond * sound + (1|speaker), data = .) %>%
summary()
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula: h2h1Int ~ cond * sound + (1 | speaker)
Data: .
REML criterion at convergence: 764.3
Scaled residuals:
Min 1Q Median 3Q Max
-2.5323 -0.5911 0.0288 0.5910 3.9947
Random effects:
Groups Name Variance Std.Dev.
speaker (Intercept) 7.859 2.803
Residual 18.403 4.290
Number of obs: 132, groups: speaker, 9
Fixed effects:
Estimate Std. Error df t value Pr(>|t|)
(Intercept) 6.9227 1.2619 12.7354 5.486 0.000113 ***
condIndividual words -0.7163 1.5065 59.3116 -0.475 0.636202
soundl -1.8395 1.0635 120.5669 -1.730 0.086240 .
condIndividual words:soundl -1.0728 1.5429 120.3569 -0.695 0.488192
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Correlation of Fixed Effects:
(Intr) cndInw soundl
cndIndvdlwr -0.539
soundl -0.294 0.256
cndIndwrds: 0.201 -0.448 -0.689
dataWrd %>%
mutate(duration = lDur,
speaker = factor (speaker,
levels = c ("F30", "M35", "M40", "F45", "F49", "M50",
"M52", "M60", "M69", "M75")),
sound = wordType,
sound = ifelse(sound == "l", "l", "glottolised l"),
cond = conditionNorm,
maxPulse = plsMax) %>%
lmer (maxPulse ~ cond * sound + (1|speaker), data = .) %>%
summary()
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula: maxPulse ~ cond * sound + (1 | speaker)
Data: .
REML criterion at convergence: -2051.3
Scaled residuals:
Min 1Q Median 3Q Max
-1.5578 -0.3844 -0.1034 0.2067 7.7914
Random effects:
Groups Name Variance Std.Dev.
speaker (Intercept) 8.173e-05 0.00904
Residual 2.490e-04 0.01578
Number of obs: 390, groups: speaker, 10
Fixed effects:
Estimate Std. Error df t value Pr(>|t|)
(Intercept) 0.025720 0.004542 36.970265 5.663 1.8e-06
condFree narrative -0.021775 0.004316 361.634035 -5.045 7.2e-07
condIndividual words 0.009473 0.003976 373.308820 2.383 0.01769
soundl -0.015371 0.004869 373.308820 -3.157 0.00172
condFree narrative:soundl 0.012704 0.005327 373.765992 2.385 0.01758
condIndividual words:soundl -0.008494 0.005623 373.308820 -1.511 0.13173
(Intercept) ***
condFree narrative ***
condIndividual words *
soundl **
condFree narrative:soundl *
condIndividual words:soundl
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Correlation of Fixed Effects:
(Intr) cndFrn cndInw soundl cndFn:
condFrnrrtv -0.684
cndIndvdlwr -0.657 0.691
soundl -0.536 0.564 0.612
cndFrnrrtv: 0.497 -0.638 -0.560 -0.914
cndIndwrds: 0.464 -0.489 -0.707 -0.866 0.792
Praat script that extracts:
form Data extracton parameters
# sound, word, production type (token), speaker - interval tiers
# pulse - point tier
comment Number of the sound tier
integer sndTier 1
comment Number of the word tier
integer wrdTier 2
comment Number of the production type tier
integer tknTier 3
comment Number of the speaker tier
integer spkTier 6
comment Number of the pulse tier
integer plsTier 7
comment Path to formant extraction data
text formantFile _ Formant_Extraction_Parameters.txt
comment Path to save spectrograms
text path C:\Users\...
endform
soundInitial = selected ("Sound")
txtGrid = selected ("TextGrid")
Edit
# ---- delete the initial word "Sound " from the file name
select soundInitial
outFileP$ = selected$ ()
len = length: outFileP$
outFileP$ = right$: outFileP$, len - 6
# ---- make output file names
outFileI$ = outFileP$ + "_Intensity.txt" ; intensities between pulses
outFileIN$ = outFileP$ + "_Intensity_Norm.txt" ; normalized intensities between pulses
outFileP$ = outFileP$ + "_Pulses and Formants.txt" ; pulse timings
; formants correspond to target sounds
; f1hz f1db f2hz f2db f3hz f3db
# ---- resample the sound
select soundInitial
Resample... 16000 50
sound = selected("Sound")
# ---- get editor name
select txtGrid
txtGridName$ = selected$ ()
editorName$ = string$(txtGrid)
editorName$ = editorName$ + ". " + txtGridName$
# ---- scaling parameters
pctRightBase = 10 ; base width of a spectrogram in Praat picture
pctRightScale = 0.5 ; base duration of a word for scaling, seconds
pctRight = 0
# ---- variables
nWord = 1 ; word counter
j = 1 ; counter for pulses
fCounter = 0 ; counter for formants
currPulse = 0 ; current pulse time
prevPulse = 0 ; previous pulse time
currWrd$ = "" ; current word which is combined letter by letter as the
# script runs through the sound layer
currWrdOut$ = "" ; current word for the output file
# ---- get formant extraction parameters
str = Read Strings from raw text file... 'formantFile$'
selectObject (str)
strNum = Get number of strings
fParams$ [1] = "" ; array of formant extraction parameters
if strNum > 1
for i to strNum
fParams$ [i] = Get string: i
endfor
endif
removeObject: str
# ---- create intensity object
selectObject: sound
intensity = To Intensity... 100 0
# ---- create pitch object
selectObject: sound
pitch = To Pitch... 0.01 75 600
# ---- extract pulses
selectObject: txtGrid
npulses = Get number of points... plsTier
pulses# = zero# (npulses)
for i to npulses
pulses# [i] = Get time of point: plsTier, i
endfor
nIntervals = Get number of intervals: sndTier ; number of intervals in the sounds tier
# ---- make headers
writeFileLine: outFileP$, "speaker", tab$, "word", tab$, "prodType", tab$, "V1start", tab$, "Cstart", tab$, "V2start", tab$, "V2end", tab$,
..."f0hz", tab$, "f0db", tab$, "h2hz", tab$, "h2db", tab$, "f1hz", tab$, "f1db", tab$,
..."f2hz", tab$, "f2db", tab$, "f3hz", tab$, "f3db", tab$, "snd", "pulseTime", tab$, "snd", tab$, "pulseTime", tab$
writeFileLine: outFileI$, "speaker", tab$, "word", tab$, "prodType", tab$, "V1start", tab$, "Cstart", tab$, "V2start", tab$, "V2end", tab$,
... "V1int", tab$, "Cint", tab$, "V2int", tab$, "CV2int", tab$,
... "CintNorm", tab$, "V2intNorm", tab$, "CV2intNorm", tab$, "snd", tab$, "intBetweenPulses", tab$, "snd", tab$, "intBetweenPulses", tab$
writeFileLine: outFileIN$, "speaker", tab$, "word", tab$, "prodType", tab$, "V1start", tab$, "Cstart", tab$, "V2start", tab$, "V2end", tab$
# ---- the main algorythm
writeInfoLine: ""
for i from 2 to (nIntervals - 1)
# -- find sounds in the sound tier
selectObject: txtGrid
snd1$ = Get label of interval: sndTier, i - 1 ; previous sound
snd2$ = Get label of interval: sndTier, i
snd3$ = Get label of interval: sndTier, i + 1 ; next sound
# limits of the previous sound
snd1Lft = Get start point: sndTier, i - 1 ; the left point of the interval
snd1Rght = Get end point: sndTier, i - 1 ; the right point of the interval
# limits of the current sound
snd2Lft = Get start point: sndTier, i
snd2Rght = Get end point: sndTier, i
# limits of the next sound
snd3Lft = Get start point: sndTier, i + 1
snd3Rght = Get end point: sndTier, i + 1
# -- check that the sounds are in the same word
wLft = Get interval at time: wrdTier, (snd1Lft + snd2Lft) / 2
wLft$ = Get label of interval: wrdTier, wLft
wRght = Get interval at time: wrdTier, (snd3Lft + snd3Rght) / 2
wRght$ = Get label of interval: wrdTier, wRght
# -- build the word in order to make leftpart_VlateralV_rightpart key
if wLft$ <> wRght$
currWrd$ = ""
else
currWrd$ = currWrd$ + snd1$
endif
if snd2$ = "l'"
snd2$ = "lˀ"
endif
if snd2$ = "ll'"
snd2$ = "llˀ"
endif
# -- check whether the lateral is between 2 sounds and that they all are within one word
# -- then extract all the necessary data
# this is because we need to have one vowel at each side of the lateral
if (snd2$ = "l" or snd2$ = "lˀ") and snd1$ <> "" and snd3$ <> "" and wLft$ = wRght$ and
...((length (snd1$) = 1 and length (snd3$) = 1) or
...(left$(snd3$,1) = "^" and length (snd1$) = 1) or
...(left$(snd1$,1) = "^" and length (snd3$) = 1))
# make output file name
currWrdOut$ = left$ (currWrd$, length (currWrd$) - length(snd1$)) ; length is reduced, because there is already the left vowel in currWrd$
currWrdOut$ = currWrdOut$ + "_" + snd1$ + snd2$ + snd3$ + "_"
z = i + 2
tmpsnd$ = Get label of interval: sndTier, z
tmpsndLft = Get start point: sndTier, z ; the left point of the interval
tmpsndRght = Get end point: sndTier, z ; the right point of the interval
tmpwrd = Get interval at time: wrdTier, (tmpsndLft + tmpsndRght) / 2
tmpwrd$ = Get label of interval: wrdTier, tmpwrd
#appendInfoLine: "i = ", fixed$(i, 0), " z = ", fixed$(z, 0), " tmpsnd ", tmpsnd$, " tmpwrd ", tmpwrd$
while tmpwrd$ = wLft$ and z <= nIntervals
currWrdOut$ = currWrdOut$ + tmpsnd$
z = z + 1
tmpsnd$ = Get label of interval: sndTier, z
tmpsndLft = Get start point: sndTier, z ; the left point of the interval
tmpsndRght = Get end point: sndTier, z ; the right point of the interval
tmpwrd = Get interval at time: wrdTier, (tmpsndLft + tmpsndRght) / 2
tmpwrd$ = Get label of interval: wrdTier, tmpwrd
#appendInfoLine: "i = ", tab$, fixed$ (i, 0), "z = ", tab$, fixed$(z, 0), tab$, "tmpsnd", tab$, tmpsnd$, tab$,
... "tmpwrd", tab$, tmpwrd$, tab$, "currWrdOut", tab$, currWrdOut$, tab$, "currWrd", tab$, currWrd$
endwhile
# borders of the target word
wLftBorder = Get start point: wrdTier, wLft
wRghtBorder = Get end point: wrdTier, wLft
currPulse = pulses# [1]
# skip all the pulses outside the desired sound
j = 1
while j <= npulses - 1 and currPulse < snd1Lft
j = j + 1
currPulse = pulses# [j]
endwhile
# we are in the first pulse of a desired VCV segment
prevPulse = currPulse
j = j + 1
currPulse = pulses# [j]
# file structure: word, token, start of sound 1, start of sound 2,
# start of sound 3, end of sound 3, sound, pulse, sound, pulse...
# get the production type (token) data
tkn = Get interval at time: tknTier, prevPulse
tkn$ = Get label of interval: tknTier, tkn
spk = Get interval at time: spkTier, prevPulse
spk$ = Get label of interval: spkTier, spk
# write general data
appendFile: outFileP$, spk$, tab$, currWrdOut$, tab$, tkn$, tab$, fixed$ (snd1Lft, 4), tab$, fixed$ (snd2Lft, 4), tab$, fixed$ (snd3Lft, 4), tab$, fixed$ (snd3Rght, 4), tab$
appendFile: outFileI$, spk$, tab$, currWrdOut$, tab$, tkn$, tab$, fixed$ (snd1Lft, 4), tab$, fixed$ (snd2Lft, 4), tab$, fixed$ (snd3Lft, 4), tab$, fixed$ (snd3Rght, 4), tab$
appendFile: outFileIN$, spk$, tab$, currWrdOut$, tab$, tkn$, tab$, fixed$ (snd1Lft, 4), tab$, fixed$ (snd2Lft, 4), tab$, fixed$ (snd3Lft, 4), tab$, fixed$ (snd3Rght, 4), tab$
# extract and write mean intensities of each sound
selectObject: intensity
snd1Int = Get mean... snd1Lft snd2Lft dB
appendFile: outFileI$, fixed$ (snd1Int, 4), tab$
snd2Int = Get mean... snd2Lft snd3Lft dB
appendFile: outFileI$, fixed$ (snd2Int, 4), tab$
snd3Int = Get mean... snd3Lft snd3Rght dB
appendFile: outFileI$, fixed$ (snd3Int, 4), tab$
snd2snd3Int = Get mean... snd2Lft snd3Rght dB
appendFile: outFileI$, fixed$ (snd2snd3Int, 4), tab$
# extract and write normalized intensities
editor: editorName$
Select: snd2Lft - 0.02, snd3Rght + 0.02
Zoom to selection
Extract selected sound (preserve times)
endeditor
tmpSound = selected ("Sound")
appendInfoLine: "snd2Int = ",fixed$(snd2Int, 2), " snd3Int = ", fixed$(snd3Int, 2), " snd2snd3Int = ", fixed$(snd2snd3Int, 2)
snd3IntNorm = 70
snd2IntNorm = snd2Int + (snd3IntNorm - snd3Int)
snd2snd3IntNorm = snd2snd3Int + (snd3IntNorm - snd3Int)
loopFlag = 1
while loopFlag = 1
appendInfoLine: "snd2IntTarget = ",fixed$(snd2IntNorm, 2), " snd3IntTarget = ", fixed$(snd3IntNorm, 2), " snd2snd3IntTarget = ", fixed$(snd2snd3IntNorm, 2)
selectObject: tmpSound
Scale intensity... snd2snd3IntNorm
tmpIntensity = To Intensity... 100 0
snd2IntNorm = Get mean... snd2Lft snd3Lft dB
snd3IntNorm = Get mean... snd3Lft snd3Rght dB
if snd3IntNorm < 69.5
snd2snd3IntNorm = snd2snd3IntNorm + 1
endif
if snd3IntNorm > 70.5
snd2snd3IntNorm = snd2snd3IntNorm - 1
endif
if snd3IntNorm >= 69.5 and snd3IntNorm <= 70.5
loopFlag = 0
endif
appendInfoLine: "snd2IntResult = ",fixed$(snd2IntNorm, 2), " snd3IntResult = ", fixed$(snd3IntNorm, 2), " snd2snd3IntResult = ", fixed$(snd2snd3IntNorm, 2)
removeObject: tmpIntensity
endwhile
appendFile: outFileI$, fixed$ (snd2IntNorm, 4), tab$
appendFile: outFileI$, fixed$ (snd3IntNorm, 4), tab$
appendFile: outFileI$, fixed$ (snd2snd3IntNorm, 4), tab$
removeObject: tmpSound
# extract formant data
if fParams$ [nWord] <> "-"
# structure of parameters: place within the l/l' sound (0.5 = middle), f1 band leftmost point,
# f1 band rightmost point, f2 left, f2 right, f3 left, f3 right
@split (" ", fParams$ [nWord])
sndPlace = number (split.array$[1])
f1Lfthz = number (split.array$[2])
f1Rghthz = number (split.array$[3])
f2Lfthz = number (split.array$[4])
f2Rghthz = number (split.array$[5])
f3Lfthz = number (split.array$[6])
f3Rghthz = number (split.array$[7])
else
sndPlace = 0.5
endif
# estimate f0 frequency. automatic estimation by Praat doesn't always work on creaky sounds
tLeft = snd2Lft + (snd2Rght - snd2Lft) * sndPlace - 0.01
tRight = snd2Lft + (snd2Rght - snd2Lft) * sndPlace + 0.01
z = j ; j is the first pulse within the lateral
pulseSum = 0
pulseNum = 0
#appendInfoLine: currWrdOut$, " j = ", fixed$(j, 0), " tLeft ", fixed$(tLeft, 3), " tRight ", fixed$ (tRight, 3), " pulse[j] = ", fixed$(pulses#[j], 3)
while pulses#[z] < tRight
#appendInfoLine: "z = ", fixed$(z, 0), " pulse[z] = ", fixed$(pulses#[z], 3)
if pulses#[z] > tLeft
pulseSum = pulseSum + pulses#[z] - pulses#[z - 1]
pulseNum = pulseNum + 1
endif
z = z + 1
endwhile
if pulseSum = 0
f0hz = undefined
else
pulseSum = pulseSum + pulses#[z] - pulses#[z - 1]
pulseNum = pulseNum + 1
f0hz = 1 / (pulseSum / pulseNum)
endif
editor: editorName$
Select: snd2Lft + (snd2Rght - snd2Lft) * sndPlace - 0.01, snd2Lft + (snd2Rght - snd2Lft) * sndPlace + 0.01 ; extract several pulses
View spectral slice
endeditor
slice = selected ("Spectrum")
To Ltas (1-to-1)
ltas = selected("Ltas")
if fParams$ [nWord] <> "-"
if f0hz <> undefined
f0Lfthz = f0hz * 0.9
f0Rghthz = f0hz * 1.1
f0db = Get maximum... f0Lfthz f0Rghthz None
f0hz = Get frequency of maximum... f0Lfthz f0Rghthz None
h2hz = f0hz * 2
h2Lefthz = h2hz * 0.9
h2Rghthz = h2hz * 1.1
h2db = Get maximum... h2Lefthz h2Rghthz None
else
f0db = undefined
f0hz = undefined
h2hz = undefined
h2db = undefined
endif
f1db = Get maximum... f1Lfthz f1Rghthz None
f1hz = Get frequency of maximum... f1Lfthz f1Rghthz None
f2db = Get maximum... f2Lfthz f2Rghthz None
f2hz = Get frequency of maximum... f2Lfthz f2Rghthz None
f3db = Get maximum... f3Lfthz f3Rghthz None
f3hz = Get frequency of maximum... f3Lfthz f3Rghthz None
# write formant data
appendFile: outFileP$, fixed$ (f0hz,0), tab$, fixed$ (f0db,0), tab$,
...fixed$ (h2hz,0), tab$, fixed$ (h2db,0), tab$,
...fixed$ (f1hz, 0), tab$, fixed$ (f1db, 0), tab$,
...fixed$ (f2hz, 0), tab$, fixed$ (f2db, 0), tab$,
...fixed$ (f3hz, 0), tab$, fixed$ (f3db, 0), tab$
else
appendFile: outFileP$, "-", tab$, "-", tab$,
..."-", tab$, "-", tab$,
..."-", tab$, "-", tab$,
..."-", tab$, "-", tab$,
..."-", tab$, "-", tab$
endif
# draw the spectral slice:
selectObject: slice
Select outer viewport: 0, 4, 0, 3
Erase all
Draw: 0, 5000, 0, 0, "yes"
# add formants
if fParams$ [nWord] <> "-"
One mark bottom: f1hz, "no", "yes", "yes", "F1 " + fixed$ (f1hz, 0)
One mark bottom: f2hz, "no", "yes", "yes", "F2 " + fixed$ (f2hz, 0)
One mark bottom: f3hz, "no", "yes", "yes", "F3 " + fixed$ (f3hz, 0)
endif
# save the slice
selectObject: txtGrid
txtGridName$ = selected$ ()
txtGridName$ = right$ (txtGridName$, length (txtGridName$) - 9)
x = (snd2Lft + snd3Lft) / 2
fname$ = path$ + txtGridName$ + ", " + currWrdOut$ + ", " + tkn$ + "_slice" + ".png"
if fileReadable (fname$)
z = 2
fname$ = path$ + txtGridName$ + ", " + currWrdOut$ + "_" + string$(z) + ", " + tkn$ + "_slice" + ".png"
while fileReadable (fname$)
z = z + 1
fname$ = path$ + txtGridName$ + ", " + currWrdOut$ + "_" + string$(z) + ", " + tkn$ + "_slice" + ".png"
endwhile
Save as 300-dpi PNG file: fname$
else
Save as 300-dpi PNG file: fname$
endif
# clear the drawing pane
Erase all
# ---- extract the sound and textgrid
# extract the sound and textgrid
editor: editorName$
Select: wLftBorder, wRghtBorder
Zoom to selection
Extract selected sound (time from 0)
endeditor
tmpSound = selected ("Sound")
editor: editorName$
Extract selected TextGrid (time from 0)
endeditor
tmpTxtGrid = selected ("TextGrid")
select tmpTxtGrid
tmpTxtGridName$ = selected$ ()
tmpEditorName$ = string$(tmpTxtGrid)
tmpEditorName$ = tmpEditorName$ + ". " + tmpTxtGridName$
# edit the textgrid. delete extra pulses
nPulses = Get number of points: plsTier
z = 1
while z <= nPulses
t = Get time of point: plsTier, z
if (t < snd1Lft - wLftBorder) or (t > snd3Rght - wLftBorder)
Remove point: plsTier, z
nPulses = Get number of points: plsTier
else
z = z + 1
endif
endwhile
# remove the data that is not required
numberOfTiers = Get number of tiers
if numberOfTiers = 8
Remove tier... 8
endif
Remove tier... 5
Remove tier... 4
# ---- draw the spectrogram ----
# scaling
pctRight = pctRightBase * (wRghtBorder - wLftBorder) / pctRightScale
Select outer viewport: 0, pctRight, 0, 4
# draw the spectrogram
select tmpSound
plus tmpTxtGrid
Edit
x = snd2Lft + (snd2Rght - snd2Lft) * sndPlace - wLftBorder
editor: tmpEditorName$
Select: 0, wRghtBorder - wLftBorder
# parameters: erase first, write name, draw selection times
# draw selection hairs, garnish
Paint visible spectrogram: "yes", "no", "yes", "yes", "yes"
endeditor
if fParams$ [nWord] <> "-"
if f0hz <> undefined
One mark left: f0hz, "yes", "yes", "yes", ""
endif
One mark left: f1hz, "yes", "yes", "yes", ""
One mark left: f2hz, "yes", "yes", "yes", ""
One mark left: f3hz, "yes", "yes", "yes", ""
Paint circle: "red", x, f1hz, 0.002
Paint circle: "red", x, f2hz, 0.002
Paint circle: "red", x, f3hz, 0.002
endif
Select outer viewport: 0, pctRight, 4, 7
editor: tmpEditorName$
Draw visible sound and TextGrid: "no", "no", "yes", "yes", "yes"
endeditor
# -- save everything
Select outer viewport: 0, pctRight, 0, 7
# the spectrogram
fname$ = left$ (fname$, length(fname$) - 10) + ".png"
Save as 300-dpi PNG file: fname$
# the sound
fname$ = left$ (fname$, length (fname$) - 4) + ".wav"
selectObject: tmpSound
Save as WAV file: fname$
# the textGrid
fname$ = left$ (fname$, length (fname$) - 4) + ".TextGrid"
selectObject: tmpTxtGrid
Save as short text file: fname$
# ---- extract data for intensity analysis
select sound
plus txtGrid
editor: editorName$
Select: snd1Lft, snd3Rght ; in order not to distort intensity
Zoom to selection
Extract selected sound (preserve times)
endeditor
tmpSndI = selected ("Sound")
select tmpSndI
Scale intensity... 70
tmpInt = To Intensity... 100 0
# ---- add normalized intensities to the output file
selectObject: tmpInt
# add mean intensities of each sound
mean_int = Get mean... snd1Lft snd2Lft dB
appendFile: outFileIN$, fixed$ (mean_int, 4), tab$
mean_int = Get mean... snd2Lft snd3Lft dB
appendFile: outFileIN$, fixed$ (mean_int, 4), tab$
mean_int = Get mean... snd3Lft snd3Rght dB
appendFile: outFileIN$, fixed$ (mean_int, 4), tab$
# ---- add data corresponding to pulses
# write pulses into the file
if j <= npulses - 1
while j <= npulses - 1 and currPulse < snd3Rght
# first, write the sound
if prevPulse < snd2Lft
appendFile: outFileP$, snd1$, tab$
appendFile: outFileI$, snd1$, tab$
appendFile: outFileIN$, snd1$, tab$
else
if prevPulse < snd3Lft
appendFile: outFileP$, snd2$, tab$
appendFile: outFileI$, snd2$, tab$
appendFile: outFileIN$, snd2$, tab$
else
appendFile: outFileP$, snd3$, tab$
appendFile: outFileI$, snd3$, tab$
appendFile: outFileIN$, snd3$, tab$
endif
endif
# write intensity
selectObject: intensity
mean_int = Get mean... prevPulse currPulse dB
appendFile: outFileI$, fixed$ (mean_int, 4), tab$
# write normalized intensity
selectObject: tmpInt
mean_int = Get mean... prevPulse currPulse dB
appendFile: outFileIN$, fixed$ (mean_int, 4), tab$
# write the last pulse into the output
appendFile: outFileP$, fixed$ (prevPulse, 4), tab$
j = j + 1
prevPulse = currPulse
currPulse = pulses# [j]
endwhile
appendFileLine: outFileI$
appendFileLine: outFileIN$
# add timing for the last pulse
appendFileLine: outFileP$, snd3$, tab$, fixed$ (prevPulse, 4)
endif
nWord = nWord + 1
# clear the trash
removeObject: slice
removeObject: ltas
removeObject: tmpSndI
removeObject: tmpInt
removeObject: tmpTxtGrid
removeObject: tmpSound
endif
endfor
removeObject: intensity
removeObject: pitch
removeObject: sound
selectObject: soundInitial, txtGrid
appendInfoLine: "Done!"
# .sep$ - separator, .str$ the string to be separated
procedure split (.sep$, .str$)
.strlen = length (.str$)
.sep = index (.str$, .sep$)
.seplen = length (.sep$)
.length = 1
while .sep > 0
.part$ = left$ (.str$, .sep - 1)
.str$ = right$ (.str$, length (.str$) - .sep - .seplen + 1)
.sep = index (.str$, .sep$)
.array$ [.length] = .part$
.length = .length + 1
endwhile
.array$ [.length] = .str$
endproc
A spectrogram of the /olˀa/ segment in /rolˀal/ (“clothes”) produced by the speaker F 45 in the first individual utterance of the word. Vertical lines on the waveform correspond to glottal pulses.
textgrid_to_df("data/F45_clothes_1_utterance.TextGrid") %>%
filter(tier %in% c(1, 5)) %>%
mutate(content = str_replace(content, "\\^a", "a")) ->
tg
draw_sound("data/F45_clothes_1_utterance.wav",
annotation = tg,
from = 0.10304,
to = 0.415985,
spectrum_info = FALSE)
Pulse profile corresponding to the spectrogram in Fig. 1. Black dots show the timing of each glottal pulse. Red dots always project into the middle of the interval between the two black dots. The red line shows the lengthening of the pulses in response to glottalization. The lower horizontal axis shows original pulse timing within the sound, the upper horizontal axis shows normalized timing, where the lateral is in the interval [0, 1]. Vertical dashed lines delimit sounds of the segment.
data %>%
mutate(conditionNorm = factor(conditionNorm, levels = c("Individual words", "Carrier phrase", "Free narrative"))) ->
data
tmp <- subset (data, speaker == "F45" & condition == "1" & word == "r_olˀ^a_l")
# points is a variable containing middles of intervals between pulses
# the lateral begins in point 0
# pointsOrig - middles of intervals with the beginning of the first vowel in point 0.
# pointsNorm is a variable with normalized middles of intervals between pulses,
# where the lateral is in [0, 1]
# move middles of intervals so that the left vowel begins at point 0
tmp$points <- tmp$points - dataWrd$snd1Bgn[dataWrd$speaker == "F45" & dataWrd$condition == 1 & dataWrd$word == "r_olˀ^a_l"]
# convert to milliseconds
tmp$points <- tmp$points * 1000
tmp$plsIntvl <- tmp$plsIntvl * 1000
tmp$pointsOrig <- tmp$pointsOrig * 1000
# line coordinates
ln1 <- data.frame (xLine1 = c (tmp$pointsOrig [26], tmp$pointsOrig [27]),
yLine1 <- c (0, 0))
ln2 <- data.frame (xLine2 = rep (mean (ln1$xLine1), 2),
yLine2 = c (0, ln1$xLine1[2] - ln1$xLine1[1]))
ln3 <- data.frame (xLine3 = c((ln1$xLine1[2] + ln1$xLine1[1]) / 2, 0.19 * 1000),
yLine3 = c(ln2$yLine2[2] / 2, 0.014 * 1000))
tmp2 <- subset (dataWrd, speaker == "F45" & condition == "1" & word =="r_olˀ^a_l")
tmp2$snd1Bgn <- tmp2$snd1Bgn * 1000
tmp2$snd2Bgn <- tmp2$snd2Bgn * 1000
tmp2$snd3Bgn <- tmp2$snd3Bgn * 1000
# black dots (pulse timing)
tmp3 <- data.frame (pointsOrig = c (tmp$pointsOrig, tmp$pointsOrig[nrow(tmp)] + tmp$plsIntvl[nrow(tmp)]))
tmp3 <-
tmp3 %>% filter (tmp3$pointsOrig > 50 & tmp3$pointsOrig < 251)
tmp3$pointsOrig[nrow(tmp3)] = 249.9
tmp3$label <- ""
tmp3$label[17] <- "t[i]"
tmp3$label[18] <- "t[i+1]"
tmp %>%
ggplot(aes (x = points, y = plsIntvl)) +
geom_line (aes(colour = condition)) +
geom_point(aes(colour = condition)) +
xlab ("VCV segment timing, ms") +
ylab ("interval between pulses, ms") +
ylim (0, 50) +
geom_vline(xintercept = -tmp2$snd1Bgn, linetype = "dashed",
size = 0.5) +
annotate ("text", x = 70, y = 30, label = "/o/", size = 6) +
annotate ("text", x = 150, y = 30, label = "/lˀ/", size = 6) +
annotate ("text", x = 235, y = 30, label = "/a/", size = 6) +
geom_vline(xintercept = -tmp2$snd1Bgn + tmp2$snd3Bgn, linetype = "dashed",
size = 0.5) +
theme(legend.title=element_blank(), legend.position = "bottom",
axis.text.x = element_text(size = 18),
axis.text.y = element_text(size = 18),
axis.title.x = element_text(size = 18),
axis.title.y = element_text(size = 18),
legend.text = element_text(size = 18)) +
geom_point (data = tmp3, aes (x = pointsOrig,
fill = "timing of glottal pulses, ms"), y = 0) +
geom_text(data = tmp3, aes (x = pointsOrig-1, label = label), parse = TRUE, size = 6, y = 3)+
geom_line (data = ln1, aes(x = xLine1, y = yLine1), size = 0.2) +
geom_line (data = ln2, aes(x = xLine2, y = yLine2), arrow = arrow(length=unit(0.2,"cm"), ends="both", type = "closed"), size = 0.2) +
geom_line (data = ln3, aes(x = xLine3, y = yLine3), arrow = arrow(length=unit(0.2,"cm"), ends="first", type = "closed"), size = 0.2) +
scale_color_hue(labels = c("duration of intervals between pulses, ms")) +
scale_fill_discrete(labels = c("glottal pulse timing, ms")) +
annotate ("label", x = ln3$xLine3[2] + 2,
y = ln3$yLine3[2] + 2,
label = "t[i+1] - t[i]", size = 6, parse = TRUE)+
scale_x_continuous (limits = c(50, 250), sec.axis = sec_axis ((~. / tmp2$snd3Bgn + tmp2$snd1Bgn / tmp2$snd3Bgn), breaks = c(-0.1, 0, 0.5, 1, 1.1), name = "normalized sound timing, the lateral is in [0, 1]"))
Pulse profiles for intervocalic laterals produced by speaker F45. The peaks in the beginning of /lˀ/ in individual words show closure due to tongue position in the lateral after a close vowel.
data %>%
filter (speaker == "F45",
word != "j_ilˀ^i_nno",
word != "kul_il^o_jd") %>%
mutate(plsIntvl = plsIntvl * 1000) %>%
ggplot (aes (x = pointsNorm, y = plsIntvl)) +
geom_line (aes(colour = conditionWord)) +
xlab ("sound timing, % of total, laterals are in [0, 1]") +
ylab ("pulse interval duration, ms") +
geom_vline (xintercept = 1, linetype = "dotted", color = "black") +
geom_vline (xintercept = 0, linetype = "dotted", color = "black") +
theme (legend.key.width = unit (0.5, "line"),
legend.position = "none",
axis.text.x = element_text(size = 12),
axis.text.y = element_text(size = 12),
axis.title.x = element_text(size = 12),
axis.title.y = element_text(size = 12),
strip.text.x = element_text(size = 12),
strip.text.y = element_text(size = 12)) +
scale_x_continuous(breaks = c(-2, -1, 0, 1, 2, 3), labels = c("-2", "-1", "0", "1", "2", "3")) +
scale_color_grey(start = 0.8, end = 0.2) +
annotate ("text", x = -0.7, y = 35, label = "/vowel/", size = 4.5) +
annotate ("text", x = 0.5, y = 35, label = "/lateral/", size = 4.5) +
annotate ("text", x = 2, y = 35, label = "/vowel/", size = 4.5) +
facet_grid (~conditionNorm~wordType, scales = "free")
Pulse profiles for intervocalic laterals produced by speaker M69. Note that the y-axes have different scales, the words describing sounds always stay on the same level (35 ms).
data %>%
filter (speaker == "M69") %>%
mutate(plsIntvl = plsIntvl * 1000) %>%
ggplot (aes (x = pointsNorm, y = plsIntvl)) +
geom_line (aes(colour = conditionWord)) +
xlab ("sound timing, % of total, laterals are in [0, 1]") +
ylab ("pulse interval duration, ms") +
geom_vline (xintercept = 1, linetype = "dotted", color = "black") +
geom_vline (xintercept = 0, linetype = "dotted", color = "black") +
theme (legend.key.width = unit (0.5, "line"),
legend.position = "none",
axis.text.x = element_text(size = 12),
axis.text.y = element_text(size = 12),
axis.title.x = element_text(size = 12),
axis.title.y = element_text(size = 12),
strip.text.x = element_text(size = 12),
strip.text.y = element_text(size = 12)) +
scale_x_continuous(breaks = c(-2, -1, 0, 1, 2, 3), labels = c("-2", "-1", "0", "1", "2", "3")) +
scale_color_grey(start = 0.8, end = 0.2) +
annotate ("text", x = -0.7, y = 35, label = "/vowel/", size = 4.5) +
annotate ("text", x = 0.5, y = 35, label = "/lateral/", size = 4.5) +
annotate ("text", x = 2, y = 35, label = "/vowel/", size = 4.5) +
facet_grid (~conditionNorm~wordType, scales = "free")
An example of a “silent” realization of /lˀ/ M69. Within the lateral we can see an area of a flat waveform showing full glottal constriction. The realization is the first individual utterance of /relˀa/ (“hand”).
textgrid_to_df("data/M69_hand_1_utterance.TextGrid") %>%
filter(tier %in% c(1, 5)) ->
tg
draw_sound("data/M69_hand_1_utterance.wav",
annotation = tg,
from = 0.1427,
to = 0.674,
spectrum_info = FALSE)
Timing of the longest interval between glottal pulses as a proxy for glottal constriction.
# base line: median interval between pulses for /l/ + 3 * SD
yBaseLine <- data %>% filter (wordType == "l") %>%
select (speaker, plsIntvl) %>%
group_by (speaker) %>%
summarize (avIntvl = mean (plsIntvl),
sdIntvl = sd (plsIntvl))
yBaseLine <- data.frame (yBaseLine, yIntercept = (yBaseLine$avIntvl + yBaseLine$sdIntvl * 3) * 1000)
dataWrd %>%
mutate(plsMax = plsMax * 1000) %>% # convert to milliseconds
ggplot () +
geom_point (aes (x = plsMaxPointNorm, y = plsMax, color = conditionNorm, shape = wordType), size = 1.5) +
scale_color_grey(start = 0, end = 0.7) +
geom_vline (xintercept = 0, linetype = "dashed", size = 0.5) +
geom_vline (xintercept = 1, linetype = "dashed", size = 0.5) +
geom_vline (xintercept = 0.33, linetype = "dotted", size = 0.5) +
geom_vline (xintercept = 0.66, linetype = "dotted", size = 0.5) +
geom_hline (data = yBaseLine, aes (yintercept = yIntercept), linetype = "dashed", size = 0.4) +
ylab ("duration of the longest interval between pulses, ms") +
xlab ("normalized sound timing, [0; 1] interval between the vertical lines corresponds to the lateral") +
theme(legend.title = element_blank(),
axis.text.x = element_text(size = 12),
axis.text.y = element_text(size = 12),
axis.title.x = element_text(size = 12),
axis.title.y = element_text(size = 12),
legend.text = element_text(size = 12),
strip.text.x = element_text(size = 12),
legend.position = "bottom") +
scale_x_continuous(breaks = c(-2, -1, 0, 0.33, 0.66, 1, 2, 3), labels = c("-2", "-1", "0", "1/3","2/3", "1", "2", "3")) +
ylim (0, 0.22 * 1000) +
annotate ("text", x = -1, y = 0.2 * 1000, label = "/vowel/", size = 5) +
annotate ("text", x = 0.5, y = 0.2 * 1000, label = "/lateral/", size = 5) +
annotate ("text", x = 2, y = 0.2 * 1000, label = "/vowel/", size = 5) +
facet_wrap (~speaker, ncol = 2)
Intensities of glottalized and modal laterals compared (only /la/ and /lˀa/ segments).
# only laterals followed by /a/: snd3 == "a*" | snd3 == "^a*"
# no carrier phrase: too few realizations
dataWrd %>%
filter((substr(snd3, 1,1) == "a" | substr(snd3, 1,2) == "^a"),
condition != "Carrier phrase") %>%
ggplot (aes (x = conditionNorm2, y = snd2IntNorm, color = conditionNorm2)) +
geom_point (position = position_jitter(w = 0.2, h = 0)) +
geom_boxplot (outlier.alpha = 0) +
theme (legend.title = element_blank(),
axis.text.x=element_text(angle=55, hjust=1, size = 12),
axis.text.y = element_text(size = 12),
axis.title.x = element_blank(),
axis.title.y = element_text(size = 12),
strip.text.x = element_text(size = 12),
strip.text.y = element_text(size = 12),
legend.position = "none") +
ylab ("Normalized intensity, dB") +
scale_color_grey(start=0.6, end=0.2) +
facet_wrap (~speaker, ncol=5)
An example of a lower-intensity modal realization of /lˀ/ by the speaker M52 in the carrier phrase. The word is /rolˀal/ (“clothes”).
textgrid_to_df("data/M52_clothes_carrier_phrase.TextGrid") %>%
filter(tier %in% c(1, 5)) %>%
mutate(content = str_replace(content, "\\^a", "a")) ->
tg
draw_sound("data/M52_clothes_carrier_phrase.wav",
annotation = tg,
from = 0.120225,
to = 0.392,
spectrum_info = FALSE)
dataWrd %>%
filter(str_detect(conditionNorm, "(Individual words)|(Free narrative)")) %>%
group_by(conditionNorm, snd2) %>%
summarise(n = n(),
mean = mean(snd2IntNorm),
sd = sd(snd2IntNorm)) %>%
pivot_longer(names_to = "stats", values_to = "values", n:sd) %>%
pivot_wider(names_from = c(snd2, stats), values_from = "values")
dataWrd %>%
mutate(lDur = lDur * 1000) %>% # convert to milliseconds
ggplot (aes (x = conditionNorm2, y = lDur, color = conditionNorm2)) +
geom_point (position = position_jitter(w = 0.2, h = 0)) +
geom_boxplot (outlier.alpha = 0) +
theme (legend.title = element_blank(),
axis.text.x=element_text(angle=55, hjust=0.95, size = 12),
axis.text.y = element_text(size = 12),
axis.title.x = element_blank(),
axis.title.y = element_text(size = 12),
strip.text.x = element_text(size = 12),
strip.text.y = element_text(size = 12),
legend.position = "none") +
ylab ("sound duration, ms") +
scale_color_grey(start=0.6, end=0.2) +
facet_wrap (~speaker, ncol=5)
dataWrd %>%
mutate(lDur = lDur * 1000) %>% # convert to milliseconds
group_by(conditionNorm, snd2) %>%
summarise(n = n(),
mean = mean(lDur),
sd = sd(lDur)) %>%
pivot_longer(names_to = "stats", values_to = "values", n:sd) %>%
pivot_wider(names_from = c(snd2, stats), values_from = "values")
Differences between intensities of A1-H1.
dataWrd %>%
filter ((substr (snd3,1,1) == "a" | substr (snd3,2,2) == "a"),
is.na (a1h1Int) == FALSE,
conditionNorm != "Carrier phrase",
!(speaker == "M69" & conditionNorm == "Individual words"),
!(speaker == "M50" & conditionNorm == "Individual words")) %>%
mutate(speaker = factor (speaker, levels = c("F45", "F30", "F49", "M52", "M60", "M69", "M35", "M40", "M75"))) %>%
ggplot() +
geom_point (aes (y = a1h1Int, x = conditionNorm2, color = factor("red", label = "A1-H1")), shape = 21, position = position_jitter(w = 0.2, h = 0)) +
geom_boxplot (aes (y = a1h1Int, x = conditionNorm2, color = factor("red", label = "A1-H1")), outlier.alpha = 0) +
theme (axis.text.x=element_text(angle=60, hjust=1, size = 12),
legend.position = "none",
axis.text.y = element_text(size = 12),
axis.title.x = element_text(size = 12),
axis.title.y = element_text(size = 12),
strip.text.x = element_text(size = 12),
strip.text.y = element_text(size = 12)) +
ylab ("Intensity difference, dB") +
scale_color_grey(start = 0.5, end = 0.2) +
labs (color = "") +
xlab ("") +
facet_wrap (~speaker)
Differences between intensities of A2-H1.
dataWrd %>%
filter ((substr (snd3,1,1) == "a" | substr (snd3,2,2) == "a"),
is.na (a1h1Int) == FALSE,
conditionNorm != "Carrier phrase",
!(speaker == "M69" & conditionNorm == "Individual words"),
!(speaker == "M50" & conditionNorm == "Individual words")) %>%
mutate(speaker = factor (speaker, levels = c("F45", "F30", "F49", "M52", "M60", "M69", "M35", "M40", "M75"))) %>%
ggplot() +
geom_point (aes (y = a2h1Int, x = conditionNorm2, color = factor("green", label = "A2-H1")), shape = 22, position = position_jitter(w = 0.2, h = 0)) +
geom_boxplot (aes (y = a2h1Int, x = conditionNorm2, color = factor("green", label = "A2-H1")), outlier.alpha = 0) +
theme (axis.text.x=element_text(angle=60, hjust=1, size = 12),
legend.position = "none",
axis.text.y = element_text(size = 12),
axis.title.x = element_text(size = 12),
axis.title.y = element_text(size = 12),
strip.text.x = element_text(size = 12),
strip.text.y = element_text(size = 12)) +
ylab ("Intensity difference, dB") +
scale_color_grey(start = 0.5, end = 0.2) +
labs (color = "") +
xlab ("") +
facet_wrap (~speaker)
Differences between intensities of H2-H1.
dataWrd %>%
filter ((substr (snd3,1,1) == "a" | substr (snd3,2,2) == "a"),
is.na (a1h1Int) == FALSE,
conditionNorm != "Carrier phrase",
!(speaker == "M69" & conditionNorm == "Individual words"),
!(speaker == "M50" & conditionNorm == "Individual words")) %>%
mutate(speaker = factor (speaker, levels = c("F45", "F30", "F49", "M52", "M60", "M69", "M35", "M40", "M75"))) %>%
ggplot() +
geom_point (aes (y = h2h1Int, x = conditionNorm2, color = factor("blue", label = "H2-H1")), shape = 22, position = position_jitter(w = 0.2, h = 0)) +
geom_boxplot (aes (y = h2h1Int, x = conditionNorm2, color = factor("blue", label = "H2-H1")), outlier.alpha = 0) +
theme (axis.text.x=element_text(angle=60, hjust=1, size = 12),
legend.position = "none",
axis.text.y = element_text(size = 12),
axis.title.x = element_text(size = 12),
axis.title.y = element_text(size = 12),
strip.text.x = element_text(size = 12),
strip.text.y = element_text(size = 12)) +
# ggtitle ("H2-H1 intensity difference") +
ylab ("Intensity difference, dB") +
scale_color_grey(start = 0.5, end = 0.2) +
labs (color = "") +
xlab ("") +
facet_wrap (~speaker)
A1-H1 intensity
dataWrd %>%
filter ((substr (snd3,1,1) == "a" | substr (snd3,2,2) == "a"),
is.na (a1h1Int) == FALSE,
conditionNorm != "Carrier phrase",
!(speaker == "M69" & conditionNorm == "Individual words"),
!(speaker == "M50" & conditionNorm == "Individual words")) %>%
mutate(speaker = factor (speaker, levels = c("F45", "F30", "F49", "M52", "M60", "M69", "M35", "M40", "M75"))) %>%
group_by(conditionNorm, snd2) %>%
summarise(n = n(),
mean = mean(a1h1Int),
sd = sd(a1h1Int)) %>%
pivot_longer(names_to = "stats", values_to = "values", n:sd) %>%
pivot_wider(names_from = c(snd2, stats), values_from = "values")
A2-H1 intensity
dataWrd %>%
filter ((substr (snd3,1,1) == "a" | substr (snd3,2,2) == "a"),
is.na (a1h1Int) == FALSE,
conditionNorm != "Carrier phrase",
!(speaker == "M69" & conditionNorm == "Individual words"),
!(speaker == "M50" & conditionNorm == "Individual words")) %>%
mutate(speaker = factor (speaker, levels = c("F45", "F30", "F49", "M52", "M60", "M69", "M35", "M40", "M75"))) %>%
group_by(conditionNorm, snd2) %>%
summarise(n = n(),
mean = mean(a2h1Int),
sd = sd(a2h1Int)) %>%
pivot_longer(names_to = "stats", values_to = "values", n:sd) %>%
pivot_wider(names_from = c(snd2, stats), values_from = "values")
H2-H1 intensity
dataWrd %>%
filter ((substr (snd3,1,1) == "a" | substr (snd3,2,2) == "a"),
is.na (a1h1Int) == FALSE,
conditionNorm != "Carrier phrase",
!(speaker == "M69" & conditionNorm == "Individual words"),
!(speaker == "M50" & conditionNorm == "Individual words")) %>%
mutate(speaker = factor (speaker, levels = c("F45", "F30", "F49", "M52", "M60", "M69", "M35", "M40", "M75"))) %>%
group_by(conditionNorm, snd2) %>%
summarise(n = n(),
mean = mean(h2h1Int),
sd = sd(h2h1Int)) %>%
pivot_longer(names_to = "stats", values_to = "values", n:sd) %>%
pivot_wider(names_from = c(snd2, stats), values_from = "values")
Effect plots for laterals’ intensity: condition and sound are independent variables, speaker is a random intercept.
dataWrd %>%
filter ((substr (snd3,1,1) == "a" | substr (snd3,2,2) == "a"),
conditionNorm != "Carrier phrase") %>%
mutate(cond = conditionNorm,
speaker = factor(speaker,
levels = c ("F30", "M35", "M40", "F45", "F49", "M50",
"M52", "M60", "M69", "M75")),
intensity = snd2IntNorm,
sound = wordType,
sound = ifelse(sound == "l", "l", "glottolised l")) %>%
lmer (intensity ~ cond*sound + (1|speaker), data = .) %>%
summary()
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula: intensity ~ cond * sound + (1 | speaker)
Data: .
REML criterion at convergence: 855.1
Scaled residuals:
Min 1Q Median 3Q Max
-3.4672 -0.4874 0.1502 0.6561 1.9824
Random effects:
Groups Name Variance Std.Dev.
speaker (Intercept) 3.972 1.993
Residual 12.930 3.596
Number of obs: 157, groups: speaker, 10
Fixed effects:
Estimate Std. Error df t value Pr(>|t|)
(Intercept) 68.3717 0.9087 17.8625 75.243 < 2e-16 ***
condIndividual words -6.8749 0.9861 106.3475 -6.972 2.75e-10 ***
soundl 1.6607 0.8911 144.6487 1.864 0.0644 .
condIndividual words:soundl 6.5213 1.1874 144.3826 5.492 1.74e-07 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Correlation of Fixed Effects:
(Intr) cndInw soundl
cndIndvdlwr -0.576
soundl -0.338 0.316
cndIndwrds: 0.253 -0.500 -0.751
Effect plots for creak (as proxied by maximal interval between 2 consecutive glottal pulses): condition and sound are independent variables, speaker is a random intercept.
Effect plots for laterals’ duration: condition and sound are independent variables, speaker is a random intercept.
Effect plots for intensity difference between the harmonic closest to A1 and H1: condition and sound are independent variables, speaker is a random intercept.
Effect plots for intensity difference between the harmonic closest to A2 and H1: condition and sound are independent variables, speaker is a random intercept.
Effect plots for intensity difference between H2 and H1: condition and sound are independent variables, speaker is a random intercept.
packages <- c("rmarkdown", "tidyverse", "phonfieldwork", "lme4", "lmerTest", "effects")
map_dfr(packages, function(i){
tibble(package = i,
version = paste(packageVersion(i), sep = "."))
}) %>%
arrange(package)